#include <map>
#include <algorithm>
#include <memory>
#include "randomForest.h"
#include "trainingData.h"
#include <string>
#include <iostream>

using namespace std;

/** 
 * Costruttore della classe random tree
 */
template <typename _T> RandomForest<_T>::RandomForest() : _randomTrees(0), _enableBagging(false) {
	//cout << "Creating random forest " << endl;
}


template <typename _T> void RandomForest<_T>::setEnableBagging(bool enableBagging) {
	this->_enableBagging = enableBagging;
}

template <typename _T> bool RandomForest<_T>::getEnableBagging() {
	return this->_enableBagging;
}


template <typename _T> void RandomForest<_T>::createForest(	string trainingDataPath,
															unsigned int numTrees, 
															unsigned int depth,
															unsigned char algorithm,
															bool enableBagging,
															unsigned int baggingNum) {
		
		this->_enableBagging = enableBagging;

		this->_trainingData.readTrainingData(trainingDataPath);
		/* Alloco i Random Tree */
		this->_forestSize = numTrees;
		this->_randomTrees.resize(numTrees);
		
		/* Train di tutti gli alberi della foresta */
		for(unsigned int i=0 ; i<numTrees; i++) {
			
			//cout << "Training tree " << i << endl;
			if(enableBagging) {
				TrainingData<_T> trainingDataBagging = this->_trainingData.randomFilter(baggingNum);
				(_randomTrees.at(i)).trainTree(trainingDataBagging, depth, algorithm);
				(_randomTrees.at(i)).setTrainingData(trainingDataBagging);

			} else {
				(_randomTrees.at(i)).trainTree(this->_trainingData, depth, algorithm);
			}
		}
}


/**
 * Classifica un record 
 */
template <typename _T> unsigned int RandomForest<_T>::classify(Record<_T> &record) {

	map<unsigned int, unsigned int> classFreq;

	for(unsigned int i=0 ;i<this->_forestSize; i++) {
		
		unsigned int c = (this->_randomTrees.at(i)).classify(this->_trainingData, record, this->getEnableBagging());
			
		if(classFreq.find(c) != classFreq.end()) {
			classFreq[c] ++;
		} else {
			classFreq[c]= 1;
		}
	}

	map<unsigned int, unsigned int>::iterator it_max = max_element(	classFreq.begin(), 
																	classFreq.end(), 
																	classFrequencyComparator);

	return it_max->first;
}


template <typename _T> RandomForest<_T>::~RandomForest() {
	//cout << "Destroying forest " << endl;
}

template RandomForest<float>;